package foundation.SurModel.rndForest.sample;

import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;

import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.SparseInstance;

public class ConverterData {
	
	public static Instances converterData(List<String> ColumnTypeName,ArrayList<ArrayList<Double>> data) throws Exception{
		
		Instances result = null;
		// Determine structure of the instances
		int numAttributes = ColumnTypeName.size();
		int[] attributeTypes = new int[numAttributes];
		@SuppressWarnings("unchecked")
		Hashtable<String, Double>[] nominalIndexes = new Hashtable[numAttributes];
		@SuppressWarnings("unchecked")
		ArrayList<String>[] nominalStrings = new ArrayList[numAttributes];
		for (int i = 0; i <numAttributes; i++) {
			switch (ColumnTypeName.get(i)) {
			case "STRING":
				// System.err.println("String --> nominal");
				attributeTypes[i - 1] = Attribute.NOMINAL;
				nominalIndexes[i - 1] = new Hashtable<String, Double>();
				nominalStrings[i - 1] = new ArrayList<String>();
				break;
			case "TEXT":
	          // System.err.println("Text --> string");
	          attributeTypes[i - 1] = Attribute.STRING;
	          nominalIndexes[i - 1] = new Hashtable<String, Double>();
	          nominalStrings[i - 1] = new ArrayList<String>();
	          break;
	        case "BOOL":
	          // System.err.println("boolean --> nominal");
	          attributeTypes[i - 1] = Attribute.NOMINAL;
	          nominalIndexes[i - 1] = new Hashtable<String, Double>();
	          nominalIndexes[i - 1].put("false", new Double(0));
	          nominalIndexes[i - 1].put("true", new Double(1));
	          nominalStrings[i - 1] = new ArrayList<String>();
	          nominalStrings[i - 1].add("false");
	          nominalStrings[i - 1].add("true");
	          break;
	        case "DOUBLE":
	          // System.err.println("BigDecimal --> numeric");
	          attributeTypes[i - 1] = Attribute.NUMERIC;
	          break;
	        case "BYTE":
	          // System.err.println("byte --> numeric");
	          attributeTypes[i - 1] = Attribute.NUMERIC;
	          break;
	        case "SHORT":
	          // System.err.println("short --> numeric");
	          attributeTypes[i - 1] = Attribute.NUMERIC;
	          break;
	        case "INTEGER":
	          // System.err.println("int --> numeric");
	          attributeTypes[i - 1] = Attribute.NUMERIC;
	          break;
	        case "LONG":
	          // System.err.println("long --> numeric");
	          attributeTypes[i - 1] = Attribute.NUMERIC;
	          break;
	        case "FLOAT":
	          // System.err.println("float --> numeric");
	          attributeTypes[i - 1] = Attribute.NUMERIC;
	          break;
	        case "DATE":
	          attributeTypes[i - 1] = Attribute.DATE;
	          break;
	        case "TIME":
	          attributeTypes[i - 1] = Attribute.DATE;
	          break;
	        case "TIMESTAMP":
	          attributeTypes[i - 1] = Attribute.DATE;
	          break;
	        default:
          // System.err.println("Unknown column type");
//          attributeTypes[i - 1] = Attribute.STRING;
        	 attributeTypes[i] = Attribute.NUMERIC;
        }

      ArrayList<Instance> instances = new ArrayList<Instance>();
      int rowCount = 0;
//      while (rs.next()) {
      for(int dataSize=0;dataSize<data.size();dataSize++){
        double[] vals = new double[numAttributes];
        for (int i1 = 0; i1 < numAttributes; i1++) {
          /*
           * switch (md.getColumnType(i)) { case Types.CHAR: case Types.VARCHAR:
           * case Types.LONGVARCHAR: case Types.BINARY: case Types.VARBINARY: case
           * Types.LONGVARBINARY:
           */
//          switch (md.getColumnTypeName(i)) {
          switch (ColumnTypeName.get(i)) {
          case "STRING":
//            String str = (String)data.get(dataSize).get(i1);
        	  String str = "";
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              Double index = nominalIndexes[i1 - 1].get(str);
              if (index == null) {
                index = new Double(nominalStrings[i1 - 1].size());
                nominalIndexes[i1 - 1].put(str, index);
                nominalStrings[i1 - 1].add(str);
              }
              vals[i1 - 1] = index.doubleValue();
//            }
            break;
          case "TEXT":
//            String txt = (String)data.get(dataSize).get(i1);
        	  String txt = "";
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              Double index1 = nominalIndexes[i1 - 1].get(txt);
              if (index1 == null) {

                // Need to add one because first value in
                // string attribute is dummy value.
                index1 = new Double(nominalStrings[i1 - 1].size()) + 1;
                nominalIndexes[i1 - 1].put(txt, index1);
                nominalStrings[i1 - 1].add(txt);
//              }
              vals[i1 - 1] = index1.doubleValue();
            }
            break;
          case "BOOL":
//            boolean boo = (boolean)data.get(dataSize).get(i1);
        	  boolean boo = false;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              vals[i1 - 1] = (boo ? 1.0 : 0.0);
//            }
            break;
          case "DOUBLE":
            // BigDecimal bd = rs.getBigDecimal(i, 4);
            double dd = (double)data.get(dataSize).get(i1);
            // Use the column precision instead of 4?
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              // newInst.setValue(i - 1, bd.doubleValue());
              vals[i1 - 1] = dd;
//            }
            break;
          case "BYTE":
//            byte by = (byte)data.get(dataSize).get(i1);
        	  byte by = 1;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              vals[i1 - 1] = by;
//            }
            break;
          case "SHORT":
//            short sh = (short)data.get(dataSize).get(i1);
        	  short sh = 1;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              vals[i1 - 1] = sh;
//            }
            break;
          case "INTEGER":
//            int in = (int)data.get(dataSize).get(i1);
        	  int in = 1;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              vals[i1 - 1] = in;
//            }
            break;
          case "LONG":
//            long lo = (long)data.get(dataSize).get(i1);
        	  long lo = 1;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              vals[i1 - 1] = lo;
//            }
            break;
          case "FLOAT":
//            float fl = (float)data.get(dataSize).get(i1);
            float fl = 1f;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              vals[i1 - 1] = fl;
//            }
            break;
          case "DATE":
//            Date date = (Date)data.get(dataSize).get(i1);
        	  Date date = null;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              // TODO: Do a value check here.
              vals[i1 - 1] = date.getTime();
//            }
            break;
          case "TIME":
//            Time time = (Time)data.get(dataSize).get(i1);
        	  Time time = null;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              // TODO: Do a value check here.
              vals[i1 - 1] = time.getTime();
//            }
            break;
          case "TIMESTAMP":
//            Timestamp ts = (Timestamp)data.get(dataSize).get(i1);
            Timestamp ts = null;
//            if (rs.wasNull()) {
//              vals[i - 1] = Utils.missingValue();
//            } else {
              vals[i1 - 1] = ts.getTime();
//            }
            break;
          default:
//            vals[i1 - 1] = Utils.missingValue();
        	  double dd1 = (double)data.get(dataSize).get(i1);
        	  vals[i1] = dd1;
          }
        }
        Instance newInst;
//        if (adapter.getSparseData()) {
          if (false) {
          newInst = new SparseInstance(1.0, vals);
        } else {
          newInst = new DenseInstance(1.0, vals);
        }
        instances.add(newInst);
        rowCount++;
      }
      // disconnectFromDatabase(); (perhaps other queries might be made)

      // Create the header and add the instances to the dataset
//      if (adapter.getDebug()) {
//        System.err.println("Creating header...");
//      }
      ArrayList<Attribute> attribInfo = new ArrayList<Attribute>();
      for (int i1 = 0; i1 < numAttributes; i1++) {
        /* Fix for databases that uppercase column names */
        // String attribName = attributeCaseFix(md.getColumnName(i + 1));
        String attribName = ColumnTypeName.get(i1);
        switch (attributeTypes[i1]) {
        case Attribute.NOMINAL:
          attribInfo.add(new Attribute(attribName, nominalStrings[i1]));
          break;
        case Attribute.NUMERIC:
          attribInfo.add(new Attribute(attribName));
          break;
        case Attribute.STRING:
          Attribute att = new Attribute(attribName, (ArrayList<String>) null);
          attribInfo.add(att);
          for (int n = 0; n < nominalStrings[i1].size(); n++) {
            att.addStringValue(nominalStrings[i1].get(n));
          }
          break;
        case Attribute.DATE:
          attribInfo.add(new Attribute(attribName, (String) null));
          break;
        default:
          throw new Exception("Unknown attribute type");
        }
      }
      result = new Instances("QueryResult", attribInfo,
      instances.size());
      for (int i1 = 0; i1 < instances.size(); i1++) {
        result.add(instances.get(i1));
      }
    }
      return result;
}
}